#ifndef _THERMALVIS_FEATURES_H_
#define _THERMALVIS_FEATURES_H_

#include "general_resources.h"
#include "opencv_resources.h"

#include <opencv2/video/video.hpp>
#include "improc.hpp"
#include "camera.h"

#define MAX_DETECTORS				10

void crossCheckMatching( Ptr<DescriptorMatcher>& descriptorMatcher,
                         const Mat& descriptors1, const Mat& descriptors2,
                         vector<DMatch>& filteredMatches12, int knn );

void filterTrackingsByRadialProportion(vector<Point2f>& pts1, vector<Point2f>& pts2, Mat& K, Mat& newCamMat, Mat& distCoeffs, Size& imSize, double prop = 1.00);

/// \brief		Transforms points using homography
void transformPoints(vector<Point2f>& pts1, Mat& H);

/// \brief      Implement optical flow algorithm and filtering
void trackPoints(Mat& im1, Mat& im2, vector<Point2f>& pts1, vector<Point2f>& pts2, int distanceConstraint, vector<unsigned int>& lostIndices, Mat H12 = cv::Mat(), cameraParameters camData = cameraParameters());

/// \brief      Sorts features in descending order of strength, and culls beyond a certain quantity
void sortKeypoints(vector<KeyPoint>& keypoints, unsigned int maxKeypoints = -1);

/// \brief      Prints keypoints onto a copy of an image
void displayKeypoints(const Mat& image, const vector<KeyPoint>& keypoints, Mat& outImg, const Scalar& color, int thickness = 1);

void showMatches(const Mat& pim1, vector<Point2f>& pts1, const Mat& pim2, vector<Point2f>& pts2, Mat& drawImg);

/// \brief      Prints keypoints onto a copy of an image
void displayKeypoints(const Mat& image, const vector<Point2f>& pts, Mat& outImg, const Scalar& color, int thickness = 1);

/// \brief      Prints match paths onto a copy of an image, given unfiltered points and matches structure
void drawMatchPaths(Mat& src, Mat& dst, vector<KeyPoint>& kp1, vector<KeyPoint>& kp2, vector<vector<DMatch> >& matches1to2);

/// \brief      Prints match paths onto a copy of an image, given vectors containing corresponding points
void drawMatchPaths(Mat& src, Mat& dst, vector<Point2f>& kp1, vector<Point2f>& kp2, const Scalar& color = CV_RGB(255, 0, 0));

/// \brief      Creates matrix representing descriptor distance between sets of features
void createMatchingMatrix(Mat& matchingMatrix, const Mat& desc1, const Mat& desc2);

/// \brief      Matches features between images given a matching matrix
void twoWayPriorityMatching(Mat& matchingMatrix, vector<vector<DMatch> >& bestMatches);

/// \brief      Uses a linear SVM to reweight the match distances so that they can be more effectively sorted
double reweightDistanceWithLinearSVM(double dist, double ratio, double gradient);

/// \brief      Checks whether there is sufficient spread of features in an image for effective tracking
bool checkSufficientFeatureSpread(vector<Point2f>& pts, Size matSize, int minFeaturesInImage);

/// \brief      Calculates linear SVM match distance
double calcDistance(double dist, double ratio, double *coeffs);

void sortMatches(vector<vector<DMatch> >& matches1to2);
void filterMatches(vector<vector<DMatch> >& matches1to2, double threshold);
void constrainMatchingMatrix(Mat& matchingMatrix, vector<KeyPoint>& kp1, vector<KeyPoint>& kp2, int distanceConstraint, double sizeConstraint);

void filterVectors(vector<Point2f>& pts1, vector<Point2f>& pts2, vector<uchar>& statusVec, double distanceConstraint = 10.0, bool epipolarCheck = false);

void assignMinimumRadii(vector<KeyPoint>& pts);

double estimateSalience(Mat& img, Point2f& center, double radius);
double estimateStability(Mat& img, Point2f& center, double radius);
bool constructPatch(Mat& img, Mat& patch, Point2f& center, double radius, int cells = 3);
double getValueFromPatch(Mat& patch);
double getPatchVariance(const Mat& patch) ;
void assignEigenVectorResponses(const Mat& img, vector<KeyPoint>& pts);
void assignStabilityResponses(const Mat& img, vector<KeyPoint>& pts);
void extendKeypoints(Mat& img, vector<KeyPoint>& pts, bool updateStrength, bool updateLocation);

void filterBlandKeypoints(Mat& img, vector<KeyPoint>& pts, double thresh = 3.0);

double distanceBetweenPoints(const KeyPoint& pt1, const KeyPoint& pt2);
double distanceBetweenPoints(const Point2f& pt1, const Point2f& pt2);

/// \brief		Sets flags to zero for tracked features that have too high an error
void filterTrackedPoints(vector<uchar>& statusVec, vector<float>& err, double maxError);


void randomlyReducePoints(vector<Point2f>& pts, int maxFeatures);

void markStationaryPoints(vector<Point2f>&pts1, vector<Point2f>&pts2, vector<uchar>&statusVec);

void markAbsentPoints(vector<Point2f>&pts1, vector<Point2f>&pts2, vector<uchar>&statusVec, cv::Size imSize);

void initializeDrawingColors(Scalar* kColors, Scalar* tColors, int num);

void concatenateWithExistingPoints(vector<Point2f> &pts, vector<Point2f>& kps, int size, double min_sep = 3);

bool checkRoomForFeature(vector<Point2f>& pts, Point2f& candidate, double dist = 3.0);

void reduceProximalCandidates(vector<Point2f>& existing, vector<Point2f>& candidates);

void reduceEdgyCandidates(vector<Point2f>& candidates, cameraParameters& camData);

void reduceEdgyFeatures(vector<KeyPoint>& keypoints, cameraParameters& camData);

void markBlandTracks(Mat& img, vector<Point2f>& pts, vector<uchar>& statusVec, double thresh = 3.0);

void reduceUnrefinedCandidates(vector<Point2f>& candidates);

void markUnrefinedPoints(vector<Point2f>& pts, vector<uchar>&statusVec);

void markEdgyTracks(vector<Point2f>& pts, vector<uchar>& statusVec, cameraParameters& camData);

void reduceWeakFeatures(Mat& im, vector<KeyPoint>& feats, double minResponse);

#endif
